#! /usr/bin/python
# -*- coding: utf-8 -*-
'''
 eoru.py

 Конвертор Эсперанто-Русского словаря Бориса Кондратьева
 из текстового формата в формат MOBI (Amazon Kindle/Mobipocket).

 Автор: Егор Чемисов
 Email: yegor.chemisov@gmail.com
 http://ervo.googlecode.com

 $HeadURL: http://ervo.googlecode.com/svn/trunk/eoru.py $
 $Date: 2011-04-27 18:17:32 +0000 (Wed, 27 Apr 2011) $
 $Id: eoru.py 111 2011-04-27 18:17:32Z yegor.chemisov $

'''
import os
import re
from glob import glob
from string import Template

REVISION        = re.search(r'\d+','$Rev: 111 $').group()
EORU_DATE       = '2011-04-03'

# SOURCE_ENCODING = ('rt', -1, 'cp1251')

# Загружаем исходные текстовые файлы в список сида:
# ( "имя файла без расширения", "содержимое файла")

SOURCE_TEXT = [(os.path.splitext(os.path.basename(file))[0],
                open(file, 'r', encoding='cp1251').read())
                for file in glob('text/*.txt')]

SOURCE_EORU = [(os.path.splitext(os.path.basename(file))[0],
                open(file, 'r', encoding='cp1251').read())
                for file in glob('eo-ru/*.txt')]

SOURCE_RUEO = [(file, open(file, 'r',encoding='cp1251').read())
                for file in glob('ru-eo/*.txt')]

FILE_EXT_TXT    = ".txt"
FILE_EXT_HTML   = ".html"
FILE_NAME = {'ĉ':'ch','ĝ':'gh','ĥ':'hh','ĵ':'jh','ŝ':'sh','ŭ':'uh'}

DIR_EO_RU 		= "./eo-ru/"
# Каталог, где находятся исходные текстовые файлы словаря (ĉĈĝĜĥĤĵĴŝŜŭŬ)

DIR_TEXT 		= "./text/"

DIR_MOBI 		= "./mobi/"
# В этот каталог нужно поместить управляющий файл для создания словаря: eoru.opf
# Здесь также можно разместить все дополнительные текстовые файлы для словаря
# в формате HTML (Mobipocket) и кодировке Unicode

DIR_PALM 		= "./palm/"
# В этот каталог будет скопировано содержимое каталого MOBI
# Все файлы при копировании будут сконвертированны для платформы PALM

DIR_MOBI_XHTML	= "./mobi/"
# Коталог где будут сохранены сгенерированные файлы XHTML в формате Unicode

DIR_PALM_XHTML  = "./palm/"
# Коталог где будут сохранены сгенерированные файлы XHTML в формате Palm

XHTML_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>EORU</title>
</head>
<body>
  <div>
%s
  </div>
</body>
</html>
"""
# <link href="stylesheet.css" type="text/css" rel="stylesheet" />
# <link rel="stylesheet" type="application/vnd.adobe-page-template+xml" href="page-template.xpgt"/>

TEMPLATE_ENTRY = Template(
"""<idx:entry name="vortaro">
$index
<b>$word</b> $definition
</idx:entry>""")

TEMPLATE_INDEX = Template(
    '<idx:orth value = "$key">$inflections</idx:orth><a id="$key" />')

TEMPLATE_INFLECTIONS = {
'i': Template("""
<idx:infl                       inflgrp="verbo">
<idx:iform name="preterito"         value="${root}is"/>
<idx:iform name="prezenco"          value="${root}as"/>
<idx:iform name="futuro"            value="${root}os"/>
<idx:iform name="imperativo"        value="${root}u"/>
<idx:iform name="volitivo"          value="${root}us"/>
</idx:infl>"""),
'o': Template("""
<idx:infl                       inflgrp="substantivo">
<idx:iform name="elizio"            value="${root}"/>
<idx:iform name="pluralo"           value="${root}oj"/>
<idx:iform name="akuzativo"         value="${root}on"/>
<idx:iform name="pluralakuzativo"   value="${root}ojn"/>
</idx:infl>"""),
'a': Template("""
<idx:infl                       inflgrp="adjektivo">
<idx:iform name="pluralo"           value="${root}j"/>
<idx:iform name="akuzativo"         value="${root}n"/>
<idx:iform name="pluralakuzativo"   value="${root}jn"/>
</idx:infl>"""),
'j': Template("""
<idx:infl                        inflgrp="pluralo">
<idx:iform name="akuzativo"         value="${root}n"/>
</idx:infl>""")
}

TEMPLATE_URL = Template('<a href="$f%s#$k">$w</a>' % FILE_EXT_HTML)

TILDE           = '~'
VERTICAL_BAR    = '|'
FORWARD_SLASH   = '/'
DOUBLE_BAR      = '</b>||<b>'

# Слово с двумя (.):             1     (   2    )   3    (   4    )  5
TWO_PARENTHESES = re.compile(r'([^(]*)\(([^)]*)\)([^(]*)\(([^)]*)\)(.*)')

# Patterns

CX2EO = (('cx','ĉ'), ('Cx','Ĉ'), ('gx','ĝ'), ('Gx','Ĝ'),
        ('hx','ĥ'), ('Hx','Ĥ'), ('jx','ĵ'), ('Jx','Ĵ'),
        ('sx','ŝ'), ('Sx','Ŝ'), ('ux','ŭ'), ('Ux','Ŭ'),
)
SYMBOLS = (('<<', '«'), ('>>', '»'), (r'`(.)', r'\1́'),
		('^@', '◊'), (',,',';'),
		(r'(?<=[^-])\-\-(?=[^-])', r'&mdash;'), #, ('/', '·')
)
CLEANUP = (
    (r'^((\$ )|(20)|(!!+)).*?$', ''), # Удаляем строчки со служебной информацией
    (r'{{.*?}}',    ''),    # Удаляем служебные комментарии в {{ ... }}
    (r'\n\n\n+', r'\n\n'),  # Удаляем излишние символы перевода строки
)

FIX_ISSUE24 = re.compile(r'([^.]*)([.]?)(%d?)')

currentRoot = None # базовая часть для подстановки в слова с тильдой
abcIndex = {}

def setRoot(word):
    global currentRoot
    global abcIndex
    currentRoot = word
    link2root = re.sub(r'[/|()]| I{1,3}|,.*', '', word).strip()
    abc = str.capitalize(link2root[:3])
    if abc not in abcIndex: abcIndex[abc] = link2root

# Нижеследующие функции используются в шаблоне TXT2HTM

def makeUrl(match):
    """Фомирование перекрёстной ссылки для слов заключенных в треугольные скобки

    Вход:
        Текст полученный из треугольных скобок с помощью регулярного выражения.
        Тип входного параметра: Match Objects.

    Результат:
        Код XHMTL для форматов epub & mobi.

    Возможные варианты входных параметров:
    ...
    Ссылки с собакой используются в тех случаях, когда текст ссылки не совпадает
    с адресом. Ну, в самом типичном случае ссылка типа _см._ <granda elefanto>,
    которая должна отослаться на статью elefanto, оформлена вот так:

    _см._ <elefanto@granda elefanto>.

    Две собаки в ссылке -- это отсылки на файл w. Там у нас два заголовка:
    Общеупотребительные сокращения (это mll1) и
    Сокращения названий организаций... (соответственно, mll2)
    ...
    <~eto.2>
    ...
    Пока реализовано создание только простой ссылки. <elefanto>
    """

    sp = match.group(1).split('@')
    word = FIX_ISSUE24.sub(r'\1 \3\2', sp[-1])

    if len(sp) == 3:
        fileName = 'w'
        key = sp[1]
    else:
        key = sp[0].split('.')[0].replace('(','').replace(')','')
        fileName = key[0].lower()
        if fileName in FILE_NAME: fileName = FILE_NAME[fileName]
    return TEMPLATE_URL.substitute(f = fileName, k = key, w = word)

def formatWord(match):
    """Формирование словарной статьи согласно шаблону и построение индексов.
    """
    out = {
        "word":         match.group(1),
        "definition":   match.group(2),
        "index":  ''
    }
    word = match.group(1)

    # Need to refine
    if '|' in word: setRoot(word[:word.find('|')])
    elif TILDE not in word: setRoot(word)

    index = []
    keys = word.replace(TILDE, currentRoot).split(',')
    for k in keys:
        # Чистим слово от лишних символов
        key = re.sub(r'[/|]| I{1,3}|,.*', '', k).strip()
        if '(' in key:  index.append(re.sub(r'\(.+?\)', '', key))
        if TWO_PARENTHESES.match(key):
            index.extend([TWO_PARENTHESES.sub(r'\1\2\3\5', key),
                          TWO_PARENTHESES.sub(r'\1\3\4\5', key)])
        index.append(re.sub('[()]', '', key))

    keys = []
    for key in index:
        if key[0] != '-' and len(key) > 1 and key[-1] in TEMPLATE_INFLECTIONS:
            keys.append(TEMPLATE_INDEX.substitute(
                key=key, inflections = TEMPLATE_INFLECTIONS[
                key[-1]].substitute(root=key[:-1])))
        else: keys.append(TEMPLATE_INDEX.substitute(
                key=key, inflections = ''))

    out['word'] = word.replace('/','·').replace('|',DOUBLE_BAR)
    out['index'] = ''.join(keys)
    return TEMPLATE_ENTRY.substitute(out)

TXT2HTM = (
    (r'<([-\w()]+!?)[.]?\d?>',makeUrl),
    (r'^\[([^]].+?)\](.*?)(?=\n\n|\Z|\n\[)', formatWord),
    (r'(\n\n+)(.*?)(?=\n\n|\Z)', r'\n<p>\2\n</p>'),
    (r'\{','<small>'),(r'\}','</small>'),
    (r'_([^_]+)_', r'<em>\1</em>'),
    (r'(\s)(\d\d?\.)([ :])', r'\1<b>\2</b>\3'),
#           (r'', r''),
)

def createIndex(file):
    for k in abcIndex:
        pass

    return None

def processText(data, pattern):
    """ Обработка исходного текста с помощью регулярных выражений."""
    for a, b in pattern:
        data = re.sub(a, b, data, 0, re.DOTALL | re.MULTILINE)
    return data

def eoru2mobi():
    """ Обработка текста для формата mobi & azw """

    # Обрабатываем словарные статьи
    patterns = CX2EO + SYMBOLS + CLEANUP + TXT2HTM
    mobiWords = [(a, processText(data, patterns)) for a, data in SOURCE_EORU]

    text = ''.join([data for a, data in mobiWords])
    crossLinks = set(re.findall(r'<[^/">]*>', text))
    open("crossLinks.txt", 'w', encoding='utf8').write('\n'.join(crossLinks))


    for file, data in mobiWords:
        open(DIR_MOBI + file + FILE_EXT_HTML, 'w',
        encoding='utf8').write(XHTML_TEMPLATE % data)

#    return None

    open(DIR_MOBI + "eoru.opf", 'w', encoding='utf8').write(
        open('./templates/eoru.opf', 'r', encoding='utf8').read() % EORU_DATE)

    # Вызываем программу kindlegen для генерации словаря
    print ("\nGenerating MOBI file")
    os.system('C:/KindleGen/kindlegen.exe '
              'mobi/eoru.opf  -verbose -c2 '
              '-o eoru-%s-r%s.azw > log.txt' % (EORU_DATE, REVISION))

    print ("Done!")
    return None

def main():
    eoru2mobi()
    return None

if __name__ == '__main__':
    print (__doc__)
    main()
